package elastic

import (
	"context"
	"gf/app/model"
	"github.com/elastic/go-elasticsearch/v8"
	"github.com/gogf/gf/frame/g"
	elastic "gopkg.in/olivere/elastic.v3"
	"log"
	"os"
	"strings"
	"time"
)

const (
	ArticleIndex = "jdbc-article"
)
const (
	Estype              = "_doc"
	HealthcheckInterval = 10 * time.Second
)

type EsData struct {
	Took int  `json:"took"`
	Hits Hits `json:"hits"`
}

type Shards struct {
	Total      int `json:"total"`
	Successful int `json:"successful"`
	Skipped    int `json:"skipped"`
	Failed     int `json:"failed"`
}

type Hits struct {
	Total Total     `json:"total"`
	Hits  []SubHits `json:"hits"`
}

type SubHits struct {
	Source  model.EsArticle `json:"_source"`
	Highlight  Highlight `json:"highlight"`
}

type Highlight struct {
	Title  []string `json:"title"`
	Content  []string `json:"content"`
}

type SubSource struct {
	model.Article
}
type Total struct {
	Value    int    `json:"value"`
	Relation string `json:"relation"`
}

// go-elasticsearch
func ElasticConnect() (*elastic.Client, error) {

	host := g.Cfg().GetString("es.host")
	user := g.Cfg().GetString("es.user")
	password := g.Cfg().GetString("es.password")

	client, err := elastic.NewClient(
		elastic.SetURL(host),
		elastic.SetBasicAuth(user, password),
		elastic.SetSniff(false),
		elastic.SetHealthcheckInterval(HealthcheckInterval), //将健康检查间隔设置为10秒。当请求失败时
		elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
		elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
	if err != nil {
		return client, err
	}

	return client, nil
}

// olivere/elastic.v3
func ElasticsearchConnect() (*elasticsearch.Client, error) {
	host := g.Cfg().GetString("es.host")
	user := g.Cfg().GetString("es.user")
	password := g.Cfg().GetString("es.password")

	cfg := elasticsearch.Config{
		Addresses: []string{
			host,
		},
		Username: user,
		Password: password,
	}
	es, err := elasticsearch.NewClient(cfg)
	if err != nil {
		return es, err
	}
	return es, nil
}

func Create(esIndex string, data map[string]interface{}, id string) (string, error) {
	client, err := ElasticConnect()
	if err != nil {
		return "", err
	}

	put, err := client.Index().
		Index(esIndex).
		Type(Estype).
		Id(id).
		BodyJson(data).
		Do()

	if err != nil {
		return "", err
	}

	return put.Id, nil
}



func Put(esIndex string, data map[string]interface{}, id string) (string, error) {
	client, err := ElasticConnect()
	if err != nil {
		return "", err
	}

	put, err := client.Update().
		Index(esIndex).
		Type(Estype).
		Id(id).
		Doc(data).
		Do()

	if err != nil {
		return "", err
	}

	return put.Id, nil
}

func Search(esIndex string, query string) (string, error) {
	es, err := ElasticsearchConnect()
	if err != nil {
		return "", err
	}

	//var buf bytes.Buffer
	//if err := json.NewEncoder(&buf).Encode(query); err != nil {
	//	return "", err
	//}

	res, err := es.Info()
	if err != nil {
		return "", err
	}

	res, err = es.Search(
		es.Search.WithContext(context.Background()),
		es.Search.WithIndex(esIndex),
		es.Search.WithBody(strings.NewReader(query)),
		//es.Search.WithBody(&buf),
		es.Search.WithTrackTotalHits(true),
		es.Search.WithPretty(),
		//es.Search.WithSize(1000), //限制条数最大1000条
	)
	if err != nil {
		return "", err
	}

	defer func() {
		err = res.Body.Close()
	}()

	restr := res.String()

	trim_left := strings.Trim(restr, "[200 OK]")
	jsonStr := strings.TrimSpace(trim_left)

	//返回json字符串
	return jsonStr, nil
}
